#include "threadpool.h"
#define NUMBER 2        // 在添加线程时一次添加的数量


Threadpool* create_threadpool(int min, int max, int queuesize)
{
    Threadpool *pool = (Threadpool *)calloc(1, sizeof(Threadpool));
    do
    {
        if(pool == NULL)
        {
            perror("calloc()");
            // exit(-1);
            break;
        }
        pool->MinNum = min;
        pool->MaxNum = max;
        pool->queueCapacity = queuesize;

        pool->workerID = (pthread_t *)calloc(max, sizeof(pthread_t));
        if(pool->workerID == NULL)
        {
            printf("workerid 分配失败\n");
            // return NULL;
            break;
        }
        pool->BusyNum = 0;
        pool->exitNum = 0;
        pool->SurvivalNum = min;

        // 初始化锁和条件变量
        if(pthread_mutex_init(&pool->mutex_Pool, NULL) != 0 ||
        pthread_mutex_init(&pool->mutex_Busy, NULL) != 0 || 
        pthread_cond_init(&pool->notFull, NULL) != 0 || 
        pthread_cond_init(&pool->notEmpty, NULL) != 0)
        {
            printf("锁或者条件变量初始化失败\n");
            // return NULL;
            break;
        }

        // 任务队列
        pool->taskQ = (Task *)malloc(sizeof(Task) * queuesize);
        if(pool->taskQ == NULL)
        {
            printf("动态内存分配失败\n");
            // return NULL;
            break;
        }
        memset(pool->taskQ, 0, sizeof(Task) * queuesize);

        pool->queueFront = pool->queueRear = 0;
        pool->Shutdown = 0;
        pool->queueSize = 0;

        // 创建线程
        pthread_create(&pool->managerID, NULL, manager, (void *)pool);

        // 工作线程的创建
        for(int i = 0; i < pool->MinNum; i++)
        {
            pthread_create(&pool->workerID[i], NULL, work, (void *)pool);
        }
        return pool;
    } while (0);
    
    // if(pool && pool->)
     // 释放资源
    printf("xxx\n");
    if (pool && pool->workerID) free(pool->workerID);
    if (pool && pool->taskQ) free(pool->taskQ);
    if (pool) free(pool);

    return NULL;


}


void *work(void *arg)
{
    Threadpool *pool = (Threadpool *)arg;

    // 从任务队列中取出任务并执行
    while(1)
    {
        // 先对线程池进行加锁
        pthread_mutex_lock(&pool->mutex_Pool);

        // 判断任务队列是否为空
        while(pool->queueSize == 0 && !pool->Shutdown)
        {
            // 需要阻塞等待管理者线程将任务加入任务队列
            // 利用条件变量
            pthread_cond_wait(&pool->notEmpty, &pool->mutex_Pool);

            // 判断是否需要退出一些线程
            if(pool->exitNum > 0)
            {
                pool->exitNum--;
                if(pool->SurvivalNum > pool->MinNum)
                {
                    pool->SurvivalNum--;
                    // 注意，线程被唤醒之后就拥有了锁，我们在杀死它之前先让他将锁资源释放出来，避免死锁的发生
                    pthread_mutex_unlock(&pool->mutex_Pool);
                    // pthread_exit(NULL);
                    ThreadExit(pool);
                }
            }
        }
        // 进行任务处理
        // 先判断线程池是否被关闭
        if(pool->Shutdown)
        {
            // 先释放锁资源再退出，避免死锁的发生
            pthread_mutex_unlock(&pool->mutex_Pool);
            // pthread_exit(0);
            ThreadExit(pool);
        }

        // 从任务队列中取出一个任务
        Task t;
        t.func = pool->taskQ[pool->queueFront].func;
        t.arg = pool->taskQ[pool->queueFront].arg;

        // 对头指针向后移动
        // 循环队列
        pool->queueFront = (pool->queueFront + 1) % pool->queueCapacity;
        pool->queueSize--;

        // 线程池解锁
        pthread_mutex_unlock(&pool->mutex_Pool);

        // 将生产者唤醒
        pthread_cond_signal(&pool->notFull);

        printf("线程 %ld 开始工作\n",pthread_self());
        // 对于busy加所
        pthread_mutex_lock(&pool->mutex_Busy);
        pool->BusyNum++;
        // 对busy解锁
        pthread_mutex_unlock(&pool->mutex_Busy);
        t.func(t.arg);
        free(t.arg);
        t.arg = NULL;

        // 操作完成busy要减一
        pthread_mutex_lock(&pool->mutex_Busy);
        pool->BusyNum--;
        // 对busy解锁
        pthread_mutex_unlock(&pool->mutex_Busy);
        printf("线程 %ld 结束工作\n",pthread_self());
    }
    return NULL;
}


void *manager(void *arg)
{
    Threadpool *pool = (Threadpool *)arg;
    while (!pool->Shutdown)
    {
        // 每隔3秒钟检测一次任务队列中的任务数
        sleep(3);

        // 取出线程池中任务的数量以及线程的数量
        pthread_mutex_lock(&pool->mutex_Pool);
        int queuesize = pool->queueSize;
        int liveNum = pool->SurvivalNum;
        pthread_mutex_unlock(&pool->mutex_Pool);

        // 取出线程池中忙的线程的数量
        pthread_mutex_lock(&pool->mutex_Busy);
        int busyNum = pool->BusyNum;
        pthread_mutex_unlock(&pool->mutex_Busy);

        // 添加线程
        // 定义规则：如果任务数量 > 存活的线程数 && 存活的线程数 < 线程数的最大值
        if(queuesize > liveNum && liveNum < pool->MaxNum)
        {
            // 添加线程
            pthread_mutex_lock(&pool->mutex_Pool);
            int count = 0;
            for(int i = 0; i < pool->MaxNum && count < NUMBER && pool->SurvivalNum < pool->MaxNum; i++)
            {
                // 找到可用的线程id
                if(pool->workerID[i] == 0)
                {
                    pthread_create(&pool->workerID[i],NULL, work, pool);
                    count++;
                    pool->SurvivalNum++;
                }
            }
            pthread_mutex_unlock(&pool->mutex_Pool);
        }
        // 销毁线程
        // 定义规则：如果忙的线程数 * 2 < 存活的线程数 && 存活的线程数 > 最小线程数
        if(busyNum * 2 < liveNum && liveNum < pool->MinNum)
        {
            pthread_mutex_lock(&pool->mutex_Pool);
            // 一次销毁两个线程
            pool->exitNum = NUMBER;
            pthread_mutex_unlock(&pool->mutex_Pool);

            // 让工作线程自杀
            // 唤醒阻塞的线程
            pthread_cond_signal(&pool->notEmpty);
        }
    }
    return NULL;

}

void ThreadExit(Threadpool *pool)
{
    // 获取线程id
    pthread_t tid = pthread_self();

    for(int i = 0; i < pool->MaxNum; i++)
    {
        if(tid == pool->workerID[i])
        {
            pool->workerID[i] = 0;
            printf("线程 %ld 退出\n",tid);
            break;
        }
    }
    pthread_exit(NULL);
}

void ThreadpoolAdd(Threadpool *pool, void (*fun)(void *), void *arg)
{
    pthread_mutex_lock(&pool->mutex_Pool);
    while(pool->queueSize == pool->queueCapacity && !pool->Shutdown)
    {
        // 阻塞生产者线程
        pthread_cond_wait(&pool->notFull, &pool->mutex_Pool);
    }

    if(pool->Shutdown)
    {
        pthread_mutex_unlock(&pool->mutex_Pool);
        return ;
    }

    // 添加任务
    pool->taskQ[pool->queueRear].func = fun;
    pool->taskQ[pool->queueRear].arg =  arg;
    pool->queueRear = (pool->queueRear + 1) % pool->queueCapacity;
    pool->queueSize++;

    pthread_cond_signal(&pool->notEmpty);

    pthread_mutex_unlock(&pool->mutex_Pool);
}

int Get_ThreadPool_BusyNum(Threadpool *pool)
{
    pthread_mutex_lock(&pool->mutex_Busy);
    int busyNum = pool->BusyNum;
    pthread_mutex_unlock(&pool->mutex_Busy);
    return busyNum;
}

int Get_ThreadPool_LiveNum(Threadpool *pool)
{
    pthread_mutex_lock(&pool->mutex_Pool);
    int liveNum = pool->SurvivalNum;
    pthread_mutex_unlock(&pool->mutex_Pool);
    return liveNum;
}

int ThreadPoolDestroy(Threadpool *pool)
{
    if(pool == NULL)
    {
        return -1;
    }

    // 关闭线程池
    pool->Shutdown = 1;

    // 阻塞回收管理者线程
    pthread_join(pool->managerID, NULL);

    // 唤醒被阻塞的工作者线程
    for(int i = 0; i < pool->SurvivalNum; i++)
    {
        pthread_cond_signal(&pool->notEmpty);
    }

    // printf()
    // 释放堆内存
    if(pool->taskQ != NULL)
    {
        free(pool->taskQ);
        // pool->taskQ = NULL;
    }

    if(pool->workerID != NULL)
    {
        free(pool->workerID);
        // pool->workerID = NULL;
    }

    // 销毁锁以及条件变量
    pthread_mutex_destroy(&pool->mutex_Pool);
    pthread_mutex_destroy(&pool->mutex_Busy);
    pthread_cond_destroy(&pool->notEmpty);
    pthread_cond_destroy(&pool->notFull);

    free(pool);
    pool = NULL;
    return 0;
}